22.2.1节,"Specail Bean Types In the WebApplicationContext"22.2.2,"Default DispathcerServlet Configuration"介绍了Spring MVC的特殊的bean和DispatcherServlet使用的默认实现。在这节,你将会学到另外两种配置Spring MVC的方法。叫做MVC Java配置和MVC XML命名空间。
MVC Java配置和MVC命名空间提供了相似的默认配置来覆盖DispatcherServlet的默认值。目的是为了让你不必要为大部分应用程序配置相同的配置,并且也提供更上层的构造方式来配置Spring MVC,以这样的方式作为起点更简单,也不需要了解底层的配置。
你可以根据个人的偏好选择MVC Java配置或是MVC命名空间 。你将会在之后看到,MVC Java配置更容易看到底层的配置并且可以直接对创建的Spring MVC bean更加细粒度的定义。让我们从开始学起。

22.16.1 Enabling the MVC Java Config or the MVC XML Namespace

在你的@Configuration类上添加@EnableWebMvc可以启用MVC Java配置:

@Configuration
@EnableWebMvc
public class WebConfig {
}

如果想在XML中实现这点,可以在你的DispatcherServlet上下文中(如果你没有定义DispathcerServlet上下文的话,可以在根上下文中)使用mvc:annotation-driven元素:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven/>

</beans>

上面注册了一个RequestMappingHandlerMapping,一个RequestMappingHandlerAdapter和一个ExceptionHandlerExceptionResolver(以及其他),用来支持通过带注解的控制器方法(比如@RequestMapping`@ExceptionHandler等等)处理请求。
它也激活了下面这些功能: 1. 除了JavaBeans PropertyEditors的数据绑定之外,通过ConversionService实例进行Spring 3 风格的类型转换。
2. 通过ConversionService使用@NumberFormat注解对格式化Number字段支持。
3. 通过@DateTimeFormat注解支持DateCalendarLong以及Joda Time字段的格式化
4. 如果类路径下存在JSR-303的提供者,可以支持通过@Valid验证@Controller的输入。
5. HttpMesageConvter支持@RequestMapping@ExceptionHandler方法中的@RequestBody方法参数和@RequestBody方法返回值。
下面是mvc:annotation-driven设置的完整的HttpMessageConverters列表:
a.ByteArrayHttpMessageConverter转换字节数组。
b.StringHttpMessageConverter转换字符串。
c.ResourceHttpMessageConverter将所有的媒体类型和org.springframework.core.io.Resource互转。
d.SourceHttpMessageConverter用来转javax.xml.transform.Source
e.FormHttpMessageConverter用来在表单数据和MultiValueMap<String, String>之间互转。
f.Jaxb2RootElementHttpMessageConverter用来在Java对象和XML之间互转——它会在类路径下JAXB2存在且Jackson 2 XML extension不存在时被添加。
g.MappingJackson2HttpMessageConverter转换JSON——在Jackson2存在类路径下的时候会被添加。
h.MappingJackson2XmlHttpMessageConverter用来转换XML——在类路径下存在Jackson 2 XML extension时被添加。
i.AtomFeedHttpMessageConverter转换Atom feeds——当类路径下存在Rome时被添加。
j.RssChannelHttpMessageConverter转换RSS feeds——当类路径下存在Rome时被添加。
22.16.12节,"Message Converters"了解更多馆续自定义这些默认的转换器。

Jackson JSON和XML转换器是由Jackson2ObjectMapperBuilder创建的ObjectMapper实例创建的,目的是提供更好的默认配置。
这个构造器使用下面的方式自定义Jackson的默认属性:
1.禁用DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
2.禁用MapperFeature.DEFAULT_VIEW_INCLUSION
如果下面这个模块在类路径下被检测到,那么也会被自动注册:
1.jackson-datatype-jdk7:提供对诸如java.nio.file.Path这样的Java 7的支持。
2.jackson-datatype-joda:支持Joda-Time类型。 3.jackson-datatype-jsr310:支持Java 8 Date & Time API类型。
4.jackson-datatype-jdk8:支持其他Java 8类型,比如Optional

22.16.2 Customzing the Provided Configuration

你可以通过轻易的实现WebMvcConfigurer或是继承WebMvcConfigurerAdapter并覆盖你需要的方法来在Java中自定义默认的配置:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    // Override configuration methods...
}

要自定义<mvc:annotation-driven/>的默认配置,请检查它支持的属性和子元素。你可以查看Spring MVC XML schema或是使用你IDE的代码提示功能查看它可用的属性和子元素。

22.16.3 Conversion and Formatting

默认内置NumberDate类型的格式化器提供了对@NumberFormat@DateTimeFormat注解的支持。如果Joda Time存在于类路径中,则还会安装队Joda Time格式化的全面支持。为了注册formatters和converters,你可以覆盖addFormatters方法:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ...
    }
}

如果在MVC命名空间中添加了<mvc:annotation-driven>,相同的默认配置也会被应用。如果你想注册自定义的formatters和converters,只需要提供ConversionService

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven conversion-service="conversionService"/>

    <bean id="conversionService"
            class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="org.example.MyConverter"/>
            </set>
        </property>
        <property name="formatters">
            <set>
                <bean class="org.example.MyFormatter"/>
                <bean class="org.example.MyAnnotationFormatterFactory"/>
            </set>
        </property>
        <property name="formatterRegistrars">
            <set>
                <bean class="org.example.MyFormatterRegistrar"/>
            </set>
        </property>
    </bean>

</beans>

更多关于使用FormatterRegistrars见第9.6.4节,"FormatterRegistrar SPI"FormattingConversionServiceFactoryBean

22.16.4 Validation

Spring提供了Validator接口用来在应用程序中任何一层中校验。在Spring MVC中,你可以用一个全局的Validator实例配置,当控制器方法参数中有@Valid或是@Validated时,该实例就会被使用,或者通过@InitBinder方法在控制器内部创建本地Validator。全局和本地的校验器可以组合起来提供复合校验。
Spring也通过LocalValidatorFactoryBean支持了JSR-303/JSR-349 Bean Validation,LocalValidatorFactoryBean用来将Springorg.springframework.validation.Validator接口适配成Bean Validation javax.validation.Validator约定。这个类可以插入Spring MVC作为全局的校验器,这将在下节描述。
默认情况下,在Spring MVC中使用@EnableWebMvc或是<mvc:annotation-driven>时,如果类路径下存在Bean Validation提供者(比如Hibernate Validator),会通过LocalValidatorFactoryBean自动注册Bean Validation验证的支持。

有时候将LocalValidatorFactoryBean注入到控制器或者其他类中会让代码便捷。最简单的方式就是声明你自己的@Bean并加上@Primary避免和MVC Java Config提供的冲突。如果你喜欢使用MVC Java配置,你需要覆盖WebMvcConfigurationSupportmvcValidator方法,并声明方法显示的返回LocalValidatorFactory而不是Validator。见22.16.13,"Advanced Customizations with MVC Java Config"获得如何拓展配置的信息。

你可以选择配置你自己的全局Validator实例:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public Validator getValidator(); {
        // return "global" validator
    }
}

或者在XML中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven validator="globalValidator"/>

</beans>

为了将本地校验器结合全局校验器使用,只需要简单添加一个或多个本地的校验器:

@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new FooValidator());
    }

}

通过这些简单配置,无论何时出现了Valid或是Validated方法参数,它都会被配置的校验器校验。任何校验失败都会被暴露在通过方法参数传递过来的BindResult中,并且也可以在Spring MVC HTML视图被渲染。

22.16.5 Interceptors

你可以为所有进来的请求或是某些特定的URL路径的请求配置HandlerInterceptors或是WebRequestInterceptors
下面是在Java中注册拦截器的例子:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleInterceptor());
        registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }

}

或者是在XML中使用<mvc:interceptors>元素:

<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/admin/**"/>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/secure/*"/>
        <bean class="org.example.SecurityInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

22.16.6 Content Negotiation

你可以配置Spring MVC如何探测请求的媒体类型。有效的选择是在URL路径中检查文件拓展名,检查"Accept"头,或是特定的查询参数,或者是没有指定请求的时候返回默认的内容类型。默认的请求URI的路径拓展名会先被检查然后在检查"Accept"头。
如果类路径上存在对应的依赖,那么MVC Java配置和MVC命名空间会默认注册jsonxmlrssatom。其他的路径拓展媒体类型映射可以通过显式注册实现,这也具有将它们列入白名单防止RFD攻击的效果(详见"Suffix Pattern Matching and RFD")。
下面是一个通过MVC Java配置自定义内容选项的例子:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.mediaType("json", MediaType.APPLICATION_JSON);
    }
}

在MVC命名空间中,<mvc:annotation-driven>元素有一个content-negotiation-manager属性,该属性需要一个ContentNegotiationManager,这又可以通过ContentNegotiationManagerFactoryBean

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

如果不适用MVC Java配置或是MVC命名空间,你需要创建一个ContentNegotiationManager的实例,并用它来配置RequestMappingHandlerMapping来实现请求的映射,以及RequestMappingHandlerAdapterExceptionHandlerExceptionResolver来实现内容协商。
请注意,ContentNegotiatingViewResolver现在也可以用ContentNegotiationManager配置,因此你可以在Spring MVC中使用一个实例。
在更高级的情况下,配置多个ContentNegotiationManager实例可能会很有用,这些实例可以包含自定义的ContentNegotiationStrategy的实现。比如,你可以用ContentNegotiationManager配置一个用来处理请求媒体类型为"application/json"ExceptionHandlerExceptionResolver。或者当没有指定请求的媒体类型时,你希望插入一个自定义的策略来选择默认的媒体类型(比如,XML或是JSON)。

22.16.7 View Controllers

这是一个定义ParameterizableViewController的快捷方式,可以在调用时立即转发到视图。它用来在生成响应前没有Java控制器逻辑需要执行的情况。
比如,将"/"请求转发到"home"的Java实现:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("home");
    }
}

在XML中可以通过<mvc:view-controller>元素实现相同的功能:

<mvc:view-controller path="/" view-name="home"/>

22.16.8 View Resolvers

MVC配置简化了视图解析器的配置。
下面是Java配置的一个例子,它使用FreeMarker HTML模板和Jackson作为JSON呈现的默认View

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.jsp();
    }
}

在XML也可以配置:

<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:jsp/>
</mvc:view-resolvers>

注意,FreeMarker,Velocity,Tiles,Groovy Markup和其他模板也需要配置底层的视图技术。
MVC命名空间提供了专门的元素。比如,FreeMarker:

<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:freemarker cache="false"/>
</mvc:view-resolvers>

<mvc:freemarker-configurer>
    <mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>

在Java配置中,只需要添加对应的“配置”Bean:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.freeMarker().cache(false);
    }

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("/WEB-INF/");
        return configurer;
    }
}

22.16.9 Serving of Resources

这个选项允许Resource列表中特定URL的静态资源请求被ResourceHttpRequestHandler处理。这提供了一种便捷的方式来处理web应用程序根路径以外的静态资源,包括类路径上的。cache-period属性可以用来设置过期的时间(建议为Page Speed和YSlow等优化工具的值设置为1年)一直与让他们更有效的被客户端使用。该处理器还可正确评估Last-Modified标头(如果存在),以便根据情况返回304状态码,从而避免由客户端缓存的资源造成不必要的开销。比如,想要使得web应用根路径下的public-resource中的/resoures/**来处理资源请求,你可以这么使用:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
    }

}

如果是在XML中,你可以这么做:

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

为了让这些资源的有效期为1年,确保最大化使用浏览器缓存并降低浏览器的HTTP请求,你可以:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
    }

}

或是在XML中:

<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>

更多信息,见HTTP caching support for static resources
mapping属性一定要是Ant风格的样式,可以被SimpleUrlHandlerMapping使用,location属性一定要指定至少一个合法的资源路径。多个资源路径可以通过逗号分隔符属性列表来指定。对一个请求,将按照指定顺序来检查指定路径下是否存在资源。比如,你想让来自web应用根路径和类路径下任何jar中的/META-INF/public-web-resources/的资源被启用,可以:

@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
    }

}

在XML中。你可以:

<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>

当部署应用程序的新版本时可能会更改资源时,建议将版本字符串并入用于请求资源的映射模式,以便强制客户端请求新部署的应用程序资源版本。框架内置了对带版本的URL的支持,可以在资源处理中配置资源链来启用。这个资源链由多个ResourceResolver实例组成,后面又跟着一个或多个ResourceTransformer实例。他们一起提供了解析和资源转换的功能。
内置的VersionResourceResolver可以配置不同的策略。比如,FixedVersionStrategy可以使用一个属性,一个日期,或是其他作为版本。ContentVersionStrategy使用由资源的内容计算而得MD5码(也叫“指纹”URL)。请注意,在服务资源时,VersionResourceResolver将自动使用已解析的版本字符串作为HTTP ETag标头值。
ContentVersionStrategy是一个很好的默认选择,除非无法使用它时(例如,javascript模块加载器)。你可以想下面这样为不同的样式配置不同的版本策略。请记住,计算基于内容的版本代价是昂贵的,因此在生产环境中应该启用医院连缓存。
Java配置例子:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public-resources/")
                .resourceChain(true)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    }
}

XML的例子:

<mvc:resources mapping="/resources/**" location="/public-resources/">
    <mvc:resource-chain>
        <mvc:resource-cache/>
        <mvc:resolvers>
            <mvc:version-resolver>
                <mvc:content-version-strategy patterns="/**"/>
            </mvc:version-resolver>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>

为了上面的配置能够生效,应用程序还需要呈现带版本的URL。最简单的方式是配置ResourceUrlEncodingFilter来封装响应并覆盖他的encodeURL方法。这在JSPs,FreeMarker,Velocity,和任意其他调用响应的encodeURL方法的视图科技中都可以使用。应用也可以选择直接注入和使用ResourceUrlPRoviderbean,它会自动被MVC Java配置和MVC名某个空间声明。
Webjars也支持WebJarsResourceResolver,当类路径上存在"org.webjars:webjars-locator"库是时,它会被自动注册。这个解析器允许资源链解析版本不可知的库,比如HTTP GET请求"GET /jquery/jquery.min.js"会返回"/jquery/1.2.0/jquery.min.js"。它对模板中重写的资源URL同样有效<script src="/jquery/jquery.min.js"/> → <script src="/jquery/1.2.0/jquery.min.js"/>

22.16.10 Default Servlet

这允许将DispatcherServlet映射到“/”(从而覆盖容器默认Servlet的映射),同时仍允许静态资源请求由容器的默认Servlet处理。它使用“/**”的URL映射和比其他优先级的URL映射来配置DefaultServletHttpRequestHandler
这个处理器将会分发所有的请求到默认的Servlet,因此它要在其他所有的URLHandlerMappings之后。如果你使用<mvc:annotation-driven>或是你选择设置自己的HandlerMapping实例,请确保将它的order属性设置的比DefaultServletHttpRequestHandler的值(为Integer.MAX_VALUE)要小。
使用默认的设置启用这个特性:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

或是在XML中:

<mvc:default-servlet-handler/>

对于重写“/”Servlet映射的警告是默认的RequestDispatcher是通过名称而不是通过路径来检索。DefaultServletHttpRequestHandler会在容器启动时尝试使用大部分Servlet容器(包括Tomcat, Jetty,GlassFish,JBoss,Resin,Weblogic和WebSphere)已知的名称列表来自动检测默认的默认的Servlet。如果默认的Servlet被自定义配置成了不同的名字,或是使用一个不同Servlet容器,而这个容器默认的Servlet名字并不知道,那么就需要显式的提供这个Servlet的名字,像下面的代码:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable("myCustomDefaultServlet");
    }

}

或是在XML中:

<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>

22.16.11 Path Matching

它允许你自定义URL映射和路径匹配相关的设置。详细细节请看PatchMatchConfirgurer API。
下面是Java配置的例子:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setUseSuffixPatternMatch(true)
            .setUseTrailingSlashMatch(false)
            .setUseRegisteredSuffixPatternMatch(true)
            .setPathMatcher(antPathMatcher())
            .setUrlPathHelper(urlPathHelper());
    }

    @Bean
    public UrlPathHelper urlPathHelper() {
        //...
    }

    @Bean
    public PathMatcher antPathMatcher() {
        //...
    }

}

在XML中,可以用<mvc:path-matching>元素:

<mvc:annotation-driven>
    <mvc:path-matching
        suffix-pattern="true"
        trailing-slash="false"
        registered-suffixes-only="true"
        path-helper="pathHelper"
        path-matcher="pathMatcher"/>
</mvc:annotation-driven>

<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>

22.16.12 Message Converters

在Java配置中自定义HttpMessageConverter可以通过重写configureMesageConverters()替换Spring MVC创建的默认的转换器,或是如果你只想自定义它们或是添加额外的转换器,可以通过重写extendMessageConverters()
下面是添加Jackson JSON和用一个带自定义的ObjectMapper的XML转换器替换默认转换器的例子:

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
                .modulesToInstall(new ParameterNamesModule());
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
    }

}

这个例子中,Jackson2ObjectMapperBuilder用来为MappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter创建一个通用的配置,并启用了缩进空能,自定义日期格式和注册jackson-module-parameter-names来支持访问参数名称(Java 8的特性)。

通过Jackson XML启用缩进支持除了需要jackson-dataformat-xml之外还要woodstox-core-asl依赖。

其他可用的感兴趣的Jackson模块: 1. jackson-datatype-money:支持javax.money类型(非官方模块) 2. jackson-datatype-hibernate:支持Hibernate特定的类型和属性(包括惰性加载切面)

XML中也可以做到这些配置:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper"/>
        </bean>
        <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
            <property name="objectMapper" ref="xmlMapper"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
      p:indentOutput="true"
      p:simpleDateFormat="yyyy-MM-dd"
      p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>

<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>

22.16.13 Advanced Customizations with MVC Java Config

正如你从上面的例子中所见,MVC Java配置和MVC命名空间提供了高层级的构建,不需要你知道底层为你所创建的bean的知识。它让你更关注你应用的需求。然而,有时候你需要更细粒度的控制或是你可能希望了解底层的配置。
为了更细粒度的控制,首先是看底层所创建的bean。在MVC Java配置中,你可以看Java文档和WebMvcConfigurationSupport@Bean方法。这个类中的配置通过@EnableWebMvc注释自动引入。事实上,如果你打开@EnableWebMvc,你会看见@Import声明。
然后你需要自定义WebMvcConfigurationSupport中创造的属性或是用你自己的实例。这需要两方面——移除@EnableWebWvc注释为了防止引入,然后继承DelegatingWebMvcConfigurationWebMvcConfigurationSupport的子类。下面是一个例子:

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        // ...
    }

    @Override
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        // Create or let "super" create the adapter
        // Then customize one of its properties
    }

}

一个应用程序应该只有一个继承自DelegatingWebMvcConfiguration的配置或是一个@EnableWebMvc注解的类,因为它们都会注册一些相同的底层的bean。
使用这种方式修改bean并不会影响你使用本节前面所展示的更层次的构建。WebMvcConfigurerAdapter子类和WebMvcConfigurer实现任然会被使用。

22.16.14 Advanced Customizations with the MVC Namespace

在MVC命名空间中用你自己创建的配置实现更细粒度的控制有点难。
如果你需要这么做,请考虑配置一个BeanPostProcessor来根据类型检测你需要的bean,并修改它们的属性而不是拷贝一份它提供的配置。比如:

@Component
public class MyPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        if (bean instanceof RequestMappingHandlerAdapter) {
            // Modify properties of the adapter
        }
    }

}

注意,为了MyPostProcessor能被检测到,它需要被包含在<component scan>中,或者你也可以在XML中显式做Bean的声明。